package com.mail.utils;

import com.mail.dto.SendEmailDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.mail.*;
import javax.mail.internet.*;
import javax.mail.util.ByteArrayDataSource;
import java.io.*;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.regex.Pattern;

/**
 * @Discription：邮件发送工具类
 */
@Slf4j
public class MailSendUtil {

        /**
         * 邮箱正则表达式
         */
        static final Pattern pattern = Pattern.compile("^([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)$");

        /**
         * 发送带附件的邮件
         *
//         * @param sendMail        发件人邮箱
//         * @param sendMailPwd     发件人密码（授权码）
//         * @param sendMailName    发件人昵称(可选)
//         * @param receiveMail     收件人邮箱
//         * @param receiveMailName 收件人昵称(可选)
//         * @param sendSMTPHost    发件人邮箱的 SMTP 服务器地址, 必须准确, 不同邮件服务器地址不同, 一般(只是一般, 绝非绝对)格式为: smtp.xxx.com
//         * @param title           邮件主题
//         * @param content         邮件正文
//         * @param files           附件文件集合
//         * @param port            邮件服务器发送邮件端口
         *
         */
        public static String sendFileMail(SendEmailDto sendEmailDto) {
                String port=sendEmailDto.getPort();
                String sendMail=sendEmailDto.getSendMail();
                String sendMailPwd=sendEmailDto.getSendMailPwd();
                String title=sendEmailDto.getTitle();
                String content=sendEmailDto.getContent();
                String sendMailName=sendEmailDto.getSendMailName();
                MultipartFile files=sendEmailDto.getFiles();
                String[] receiveMail=sendEmailDto.getReceiveMail();
                String sendSMTPHost =sendEmailDto.getSendSMTPHost();
                String receiveMailName=sendEmailDto.getReceiveMailName();

                Session session = createSSLSession(sendSMTPHost, port, sendMailName, sendMailPwd);

                // 3. 创建一封邮件
                MimeMessage message;
                try {
                        message = createMimeMessage(session, sendMail, sendMailName, receiveMail, receiveMailName, title, content);
                        // 5. Content: 邮件正文（可以使用html标签）（内容有广告嫌疑，避免被邮件服务器误认为是滥发广告以至返回失败，请修改发送内容）
                        MimeMultipart mm = new MimeMultipart();
                        MimeBodyPart text = new MimeBodyPart();
                        text.setContent(content, "text/html;charset=UTF-8");
                        mm.addBodyPart(text);
                        if(!(files ==null)) {
//                                for(MultipartFile f: files) {
                                        // MultipartFile 转化成 InputStream
                                        byte[] byteArr = files.getBytes();
                                        InputStream inputStream = new ByteArrayInputStream(byteArr);
                                        MimeBodyPart attachment = new MimeBodyPart();
                                        DataSource source = new ByteArrayDataSource(inputStream, "application/msexcel");
                                        attachment.setDataHandler(new DataHandler(source));
                                        // 设置附件的文件名（需要编码）
                                        attachment.setFileName(MimeUtility.encodeText(files.getOriginalFilename()));
                                        // 10. 设置文本和 附件 的关系（合成一个大的混合"节点" / Multipart ）
                                        // 如果有多个附件，可以创建多个多次添加
                                        mm.addBodyPart(attachment);
//                                }
                        }
                        message.setContent(mm);
                        message.saveChanges();
                        // 4. 根据 Session 获取邮件传输对象
                        Transport transport = session.getTransport("smtp");
                        transport.connect(sendSMTPHost, sendMail, sendMailPwd);
                        // 6. 发送邮件, 发到所有的收件地址, message.getAllRecipients() 获取到的是在创建邮件对象时添加的所有收件人, 抄送人, 密送人
                        transport.sendMessage(message, message.getAllRecipients());
                        // 7. 关闭连接
                        transport.close();
                        return null;
                } catch (Exception e) {
                        System.err.println("邮件发送失败的原因是："+e.getMessage());
                        System.err.println("具体的错误原因");
                        e.printStackTrace(System.err);
                        return e.getMessage();
                }

        }


        public static String sendTextMail(SendEmailDto sendEmailDto) {
                String port=sendEmailDto.getPort();
                String sendMail=sendEmailDto.getSendMail();
                String sendMailPwd=sendEmailDto.getSendMailPwd();
                String title=sendEmailDto.getTitle();
                String content=sendEmailDto.getContent();
                String sendMailName=sendEmailDto.getSendMailName();
                String[] receiveMail=sendEmailDto.getReceiveMail();
                String sendSMTPHost =sendEmailDto.getSendSMTPHost();
                String receiveMailName=sendEmailDto.getReceiveMailName();

                Session session = createSSLSession(sendSMTPHost, port, sendMailName, sendMailPwd);

                // 3. 创建一封邮件
                MimeMessage message;
                try {
                        message = createMimeMessage(session, sendMail, sendMailName, receiveMail, receiveMailName, title, content);
                        // 5. Content: 邮件正文（可以使用html标签）（内容有广告嫌疑，避免被邮件服务器误认为是滥发广告以至返回失败，请修改发送内容）
                        MimeMultipart mm = new MimeMultipart();
                        MimeBodyPart text = new MimeBodyPart();
                        text.setContent(content, "text/html;charset=UTF-8");
                        mm.addBodyPart(text);
                        message.setContent(mm);
                        message.saveChanges();
                        // 4. 根据 Session 获取邮件传输对象
                        Transport transport = session.getTransport("smtp");
                        transport.connect(sendSMTPHost, sendMail, sendMailPwd);
                        // 6. 发送邮件, 发到所有的收件地址, message.getAllRecipients() 获取到的是在创建邮件对象时添加的所有收件人, 抄送人, 密送人
                        transport.sendMessage(message, message.getAllRecipients());
                        // 7. 关闭连接
                        transport.close();
                        return null;
                } catch (Exception e) {
                        System.err.println("邮件发送失败的原因是："+e.getMessage());
                        System.err.println("具体的错误原因");
                        e.printStackTrace(System.err);
                        return e.getMessage();
                }

        }



        /**
         * 创建session
         */
        private static Session createSSLSession(String sendSMTPHost, String port, String userName, String pwd) {
                // 1. 创建参数配置, 用于连接邮件服务器的参数配置
                Properties props = new Properties(); // 参数配置
                props.setProperty("mail.smtp.user", userName);
                props.setProperty("mail.smtp.password", pwd);
                props.setProperty("mail.smtp.host", sendSMTPHost);
                props.setProperty("mail.smtp.port", port);
                props.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
                props.setProperty("mail.smtp.socketFactory.fallback", "false");
                props.setProperty("mail.smtp.socketFactory.port", port);
                props.put("mail.smtp.auth", "true");

                // 2. 根据配置创建会话对象, 用于和邮件服务器交互
                Session session = Session.getDefaultInstance(props, new Authenticator() {
                        //身份认证
                        @Override
                        protected PasswordAuthentication getPasswordAuthentication() {
                                return new PasswordAuthentication(userName, pwd);
                        }
                });
                session.setDebug(true); // 设置为debug模式, 可以查看详细的发送 log
                return session;
        }


        /**
         * 创建一封只包含文本的简单邮件
         *
         * @param session         和服务器交互的会话
         * @param sendMail        发件人邮箱
         * @param sendMailName    发件人昵称
         * @param receiveMail     收件人邮箱
         * @param receiveMailName 收件人昵称
         * @param title           邮件主题
         * @param content         邮件正文
         * @return
         * @throws Exception
         */
        public static MimeMessage createMimeMessage(Session session, String sendMail, String sendMailName, String[] receiveMail, String receiveMailName, String title, String content) throws Exception {
        // 1. 创建一封邮件
        MimeMessage message = new MimeMessage(session);
        // 2. From: 发件人
        message.setFrom(new InternetAddress(sendMail, sendMailName, "UTF-8"));
        // 3. To: 收件人（可以增加多个收件人、抄送、密送）
        List<InternetAddress> to = new LinkedList<>();
        for (String s : receiveMail) {
        if (pattern.matcher(s).matches()) {
        to.add(new InternetAddress(s));
        }
        }
        //Address[] addresses = new Address[]{new InternetAddress(receiveMail),new InternetAddress(receiveMail)};
        message.addRecipients(MimeMessage.RecipientType.TO, to.toArray((new InternetAddress[to.size()])));
        // 4. Subject: 邮件主题（标题有广告嫌疑，避免被邮件服务器误认为是滥发广告以至返回失败，请修改标题）
        message.setSubject(title, "UTF-8");
        // 5. Content: 邮件正文（可以使用html标签）（内容有广告嫌疑，避免被邮件服务器误认为是滥发广告以至返回失败，请修改发送内容）
        message.setContent(content, "text/html;charset=UTF-8");
        // 6. 设置发件时间
        message.setSentDate(new Date());
        // 7. 保存设置
        message.saveChanges();
        return message;
        }
        }

